use crate::fiomux::types::*;
use kspin::SpinNoIrq;
use lazyinit::LazyInit;
use crate::mem::phys_to_virt;
use memory_addr::PhysAddr;

// 全局FIO Pad控制器实例
static IOPAD_CTRL: LazyInit<SpinNoIrq<Option<FIOPadCtrl>>> = LazyInit::new();

/// 读取FIO寄存器
unsafe fn fiopad_read_reg32(base: *mut u8, reg_offset: usize) -> u32 {
    let addr = base.add(reg_offset) as *const u32;
    let val = addr.read_volatile();
    info!("Reading from IOPAD register at virtual address 0x{:x} (offset 0x{:x}): 0x{:x}", 
          addr as usize, reg_offset, val);
    val
}

/// 写入FIO寄存器
unsafe fn fiopad_write_reg32(base: *mut u8, reg_offset: usize, reg_value: u32) {
    let addr = base.add(reg_offset) as *mut u32;
    info!("Writing 0x{:x} to IOPAD register at virtual address 0x{:x} (offset 0x{:x})", 
          reg_value, addr as usize, reg_offset);
    addr.write_volatile(reg_value);
}

/// FIO多路复用初始化
///
/// 初始化FIO多路复用控制器，根据飞腾平台PHYTIUMPI_FIREFLY板卡的配置
pub fn fiomux_init() {
    // 使用fparameters.h中定义的正确基地址
    let base_phys_addr = PhysAddr::from(0x26FD2000usize);
    let base_addr = phys_to_virt(base_phys_addr).as_mut_ptr();
    info!("Initializing IOMUX controller with physical base address 0x{:x} and virtual base address 0x{:x}", 
          0x26FD2000usize, base_addr as usize);
    let ctrl = Some(FIOPadCtrl::new(base_addr));
    IOPAD_CTRL.init_once(SpinNoIrq::new(ctrl));
}

/// FIO多路复用去初始化
pub fn fiomux_deinit() {
    if IOPAD_CTRL.is_inited() {
        *IOPAD_CTRL.lock() = None;
    }
}

/// 获取IO引脚的当前复用功能
///
/// # 参数
///
/// * `pin_reg_off` - 引脚寄存器偏移量
///
/// # 返回值
///
/// 返回当前引脚的复用功能
pub fn fiopad_get_func(pin_reg_off: usize) -> FIOPadFunc {
    if !IOPAD_CTRL.is_inited() {
        return FIOPadFunc::FUNC0;
    }

    let ctrl = IOPAD_CTRL.lock();
    if let Some(ctrl) = &*ctrl {
        unsafe {
            let reg_val = fiopad_read_reg32(ctrl.base.as_ptr(), pin_reg_off);
            let func_val = fiopad_reg0_func_get(reg_val);
            match func_val {
                0 => FIOPadFunc::FUNC0,
                1 => FIOPadFunc::FUNC1,
                2 => FIOPadFunc::FUNC2,
                3 => FIOPadFunc::FUNC3,
                4 => FIOPadFunc::FUNC4,
                5 => FIOPadFunc::FUNC5,
                6 => FIOPadFunc::FUNC6,
                _ => FIOPadFunc::FUNC0, // 默认值
            }
        }
    } else {
        FIOPadFunc::FUNC0
    }
}

/// 设置IO引脚的复用功能
///
/// # 参数
///
/// * `pin_reg_off` - 引脚寄存器偏移量
/// * `func` - 要设置的复用功能
pub fn fiopad_set_func(pin_reg_off: usize, func: FIOPadFunc) {
    if !IOPAD_CTRL.is_inited() {
        info!("IOPAD controller not initialized, skipping function set");
        return;
    }

    let ctrl = IOPAD_CTRL.lock();
    if let Some(ctrl) = &*ctrl {
        unsafe {
            let current_val = fiopad_read_reg32(ctrl.base.as_ptr(), pin_reg_off);
            info!("Current value at pin offset 0x{:x}: 0x{:x}", pin_reg_off, current_val);
            
            let mut reg_val = current_val;
            // 清除原有的功能设置
            reg_val &= !FIOPAD_REG0_FUNC_MASK;
            // 设置新的功能
            reg_val |= fiopad_reg0_func_set(func as u32);
            
            info!("Setting function {:?} at pin offset 0x{:x}, new value will be 0x{:x}", func, pin_reg_off, reg_val);
            fiopad_write_reg32(ctrl.base.as_ptr(), pin_reg_off, reg_val);
            
            // 验证写入
            let verify_val = fiopad_read_reg32(ctrl.base.as_ptr(), pin_reg_off);
            info!("Verified value at pin offset 0x{:x}: 0x{:x}", pin_reg_off, verify_val);
        }
    }
}

/// 设置PWM的FIO多路复用
///
/// 根据指定的PWM ID和通道设置相应的FIO Pad多路复用功能
///
/// # 参数
///
/// * `pwm_id` - PWM控制器ID
/// * `pwm_channel` - PWM通道号
pub fn fiopad_set_pwm_mux(pwm_id: u32, pwm_channel: u32) {
    match pwm_id {
        0 => {
            // FPWM0_ID
            match pwm_channel {
                0 => {
                    fiopad_set_func(FIOPAD_AL59_REG0_OFFSET, FIOPadFunc::FUNC1); /* PWM0_OUT: func 1 */
                }
                1 => {
                    fiopad_set_func(FIOPAD_AJ57_REG0_OFFSET, FIOPadFunc::FUNC1); /* PWM1_OUT: func 1 */
                }
                _ => {}
            }
        }
        1 => {
            // FPWM1_ID
            match pwm_channel {
                0 => {
                    fiopad_set_func(FIOPAD_AG57_REG0_OFFSET, FIOPadFunc::FUNC1); /* PWM2_OUT: func 1 */
                }
                1 => {
                    fiopad_set_func(FIOPAD_AC59_REG0_OFFSET, FIOPadFunc::FUNC1); /* PWM3_OUT: func 1 */
                }
                _ => {}
            }
        }
        _ => {}
    }
}

/// 设置UART的FIO多路复用
///
/// 根据指定的UART ID设置相应的FIO Pad多路复用功能
///
/// # 参数
///
/// * `uart_id` - UART控制器ID
pub fn fiopad_set_uart_mux(uart_id: u32) {
    match uart_id {
        1 => {
            // FUART1_ID
            fiopad_set_func(FIOPAD_AW51_REG0_OFFSET, FIOPadFunc::FUNC0);
            fiopad_set_func(FIOPAD_AU51_REG0_OFFSET, FIOPadFunc::FUNC0);
        }
        2 => {
            // FUART2_ID
            fiopad_set_func(FIOPAD_A47_REG0_OFFSET, FIOPadFunc::FUNC0);
            fiopad_set_func(FIOPAD_A49_REG0_OFFSET, FIOPadFunc::FUNC0);
        }
        _ => {}
    }
}

/// 设置CAN的FIO多路复用
///
/// 根据指定的CAN ID设置相应的FIO Pad多路复用功能
///
/// # 参数
///
/// * `can_id` - CAN控制器ID
pub fn fiopad_set_can_mux(can_id: u32) {
    match can_id {
        0 => {
            // FCAN0_ID
            fiopad_set_func(FIOPAD_A41_REG0_OFFSET, FIOPadFunc::FUNC0); /* can0-tx: func 0 */
            fiopad_set_func(FIOPAD_A43_REG0_OFFSET, FIOPadFunc::FUNC0); /* can0-rx: func 0 */
        }
        1 => {
            // FCAN1_ID
            fiopad_set_func(FIOPAD_A45_REG0_OFFSET, FIOPadFunc::FUNC0); /* can1-tx: func 0 */
            fiopad_set_func(FIOPAD_C45_REG0_OFFSET, FIOPadFunc::FUNC0); /* can1-rx: func 0 */
        }
        _ => {}
    }
}

/// 设置I2S的FIO多路复用 (PD2308)
pub fn fiopad_set_i2s_mux_pd2308() {
    // These offsets match PD2308 board C config (clk/data)
    const FIOPAD_AN17_REG0_OFFSET: usize = 0xA34; // clk
    const FIOPAD_AR17_REG0_OFFSET: usize = 0xA54; // data
    fiopad_set_func(FIOPAD_AN17_REG0_OFFSET, FIOPadFunc::FUNC0);
    fiopad_set_func(FIOPAD_AR17_REG0_OFFSET, FIOPadFunc::FUNC0);
}